home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / octa209s.zip / octave-2.09 / libs / readline / search.c < prev    next >
C/C++ Source or Header  |  1995-09-19  |  9KB  |  376 lines

  1. /* search.c - code for non-incremental searching in emacs and vi modes. */
  2.  
  3. /* Copyright (C) 1992 Free Software Foundation, Inc.
  4.  
  5.    This file is part of the Readline Library (the Library), a set of
  6.    routines for providing Emacs style line input to programs that ask
  7.    for it.
  8.  
  9.    The Library is free software; you can redistribute it and/or modify
  10.    it under the terms of the GNU General Public License as published by
  11.    the Free Software Foundation; either version 1, or (at your option)
  12.    any later version.
  13.  
  14.    The Library is distributed in the hope that it will be useful, but
  15.    WITHOUT ANY WARRANTY; without even the implied warranty of
  16.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17.    General Public License for more details.
  18.  
  19.    The GNU General Public License is often shipped with GNU software, and
  20.    is generally kept in a file called COPYING or LICENSE.  If you do not
  21.    have a copy of the license, write to the Free Software Foundation,
  22.    675 Mass Ave, Cambridge, MA 02139, USA. */
  23.  
  24. #ifdef HAVE_CONFIG_H
  25. #include <config.h>
  26. #endif
  27.  
  28. #define READLINE_LIBRARY
  29.  
  30. #include <sys/types.h>
  31. #include <stdio.h>
  32.  
  33. #if defined (HAVE_UNISTD_H)
  34. #  include <unistd.h>
  35. #endif
  36.  
  37. #include "rldefs.h"
  38. #include "readline.h"
  39. #include "history.h"
  40.  
  41. #define STREQ(a, b)    (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0))
  42. #define STREQN(a, b, n)    (((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0))
  43.  
  44. #define abs(x)        (((x) > 0) ? (x) : -(x))
  45.  
  46. extern char *xmalloc (), *xrealloc ();
  47.  
  48. /* Variables imported from readline.c */
  49. extern int rl_point, rl_end, rl_line_buffer_len;
  50. extern Keymap _rl_keymap;
  51. extern int rl_editing_mode;
  52. extern char *rl_prompt;
  53. extern char *rl_line_buffer;
  54. extern HIST_ENTRY *saved_line_for_history;
  55. extern Function *rl_last_func;
  56.  
  57. /* Functions imported from the rest of the library. */
  58. extern int _rl_free_history_entry ();
  59.  
  60. static char *noninc_search_string = (char *) NULL;
  61. static int noninc_history_pos = 0;
  62. static char *prev_line_found = (char *) NULL;
  63.  
  64. /* Search the history list for STRING starting at absolute history position
  65.    POS.  If STRING begins with `^', the search must match STRING at the
  66.    beginning of a history line, otherwise a full substring match is performed
  67.    for STRING.  DIR < 0 means to search backwards through the history list,
  68.    DIR >= 0 means to search forward. */
  69. static int
  70. noninc_search_from_pos (string, pos, dir)
  71.      char *string;
  72.      int pos, dir;
  73. {
  74.   int ret, old;
  75.  
  76.   old = where_history ();
  77.   history_set_pos (pos);
  78.  
  79.   if (*string == '^')
  80.     ret = history_search_prefix (string + 1, dir);
  81.   else
  82.     ret = history_search (string, dir);
  83.  
  84.   if (ret != -1)
  85.     ret = where_history ();
  86.  
  87.   history_set_pos (old);
  88.   return (ret);
  89. }
  90.  
  91. /* Search for a line in the history containing STRING.  If DIR is < 0, the
  92.    search is backwards through previous entries, else through subsequent
  93.    entries. */
  94. static void
  95. noninc_dosearch (string, dir)
  96.      char *string;
  97.      int dir;
  98. {
  99.   int oldpos, pos;
  100.   HIST_ENTRY *entry;
  101.  
  102.   if (string == 0 || *string == '\0' || noninc_history_pos < 0)
  103.     {
  104.       ding ();
  105.       return;
  106.     }
  107.  
  108.   pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
  109.   if (pos == -1)
  110.     {
  111.       /* Search failed, current history position unchanged. */
  112.       maybe_unsave_line ();
  113.       rl_clear_message ();
  114.       rl_point = 0;
  115.       ding ();
  116.       return;
  117.     }
  118.  
  119.   noninc_history_pos = pos;
  120.  
  121.   oldpos = where_history ();
  122.   history_set_pos (noninc_history_pos);
  123.   entry = current_history ();
  124. #if defined (VI_MODE)
  125.   if (rl_editing_mode != vi_mode)
  126. #endif
  127.   history_set_pos (oldpos);
  128.  
  129.   {
  130.     int line_len;
  131.  
  132.     line_len = strlen (entry->line);
  133.     if (line_len >= rl_line_buffer_len)
  134.       rl_extend_line_buffer (line_len);
  135.     strcpy (rl_line_buffer, entry->line);
  136.   }
  137.  
  138.   rl_undo_list = (UNDO_LIST *)entry->data;
  139.   rl_end = strlen (rl_line_buffer);
  140.   rl_point = 0;
  141.   rl_clear_message ();
  142.  
  143.   if (saved_line_for_history)
  144.     _rl_free_history_entry (saved_line_for_history);
  145.   saved_line_for_history = (HIST_ENTRY *)NULL;
  146. }
  147.  
  148. /* Search non-interactively through the history list.  DIR < 0 means to
  149.    search backwards through the history of previous commands; otherwise
  150.    the search is for commands subsequent to the current position in the
  151.    history list.  PCHAR is the character to use for prompting when reading
  152.    the search string; if not specified (0), it defaults to `:'. */
  153. static void
  154. noninc_search (dir, pchar)
  155.      int dir;
  156.      int pchar;
  157. {
  158.   int saved_point, c, pmtlen;
  159.   char *p;
  160.  
  161.   maybe_save_line ();
  162.   saved_point = rl_point;
  163.  
  164.   /* Use the line buffer to read the search string. */
  165.   rl_line_buffer[0] = 0;
  166.   rl_end = rl_point = 0;
  167.  
  168.   /* XXX - this needs fixing to work with the prompt expansion stuff - XXX */
  169.   pmtlen = (rl_prompt && *rl_prompt) ? strlen (rl_prompt) : 0;
  170.   p = xmalloc (2 + pmtlen);
  171.   if (pmtlen)
  172.     strcpy (p, rl_prompt);
  173.   p[pmtlen] = pchar ? pchar : ':';
  174.   p[pmtlen + 1]  = '\0';
  175.  
  176.   rl_message (p, 0, 0);
  177.   free (p);
  178.  
  179.   /* Read the search string. */
  180.   while (c = rl_read_key ())
  181.     {
  182.       switch (c)
  183.     {
  184.     case CTRL('H'):
  185.     case RUBOUT:
  186.       if (rl_point == 0)
  187.         {
  188.           maybe_unsave_line ();
  189.           rl_clear_message ();
  190.           rl_point = saved_point;
  191.           return;
  192.         }
  193.       rl_rubout (1);
  194.       break;
  195.  
  196.     case CTRL('W'):
  197.       rl_unix_word_rubout (1, c);
  198.       break;
  199.  
  200.     case CTRL('U'):
  201.       rl_unix_line_discard (1, c);
  202.       break;
  203.  
  204.     case RETURN:
  205.     case NEWLINE:
  206.       goto dosearch;
  207.       /* NOTREACHED */
  208.       break;
  209.  
  210.     case CTRL('C'):
  211.     case CTRL('G'):
  212.       maybe_unsave_line ();
  213.       rl_clear_message ();
  214.       rl_point = saved_point;
  215.       ding ();
  216.       return;
  217.  
  218.     default:
  219.       rl_insert (1, c);
  220.       break;
  221.     }
  222.       rl_redisplay ();
  223.     }
  224.  
  225.  dosearch:
  226.   /* If rl_point == 0, we want to re-use the previous search string and
  227.      start from the saved history position.  If there's no previous search
  228.      string, punt. */
  229.   if (rl_point == 0)
  230.     {
  231.       if (!noninc_search_string)
  232.     {
  233.       ding ();
  234.       return;
  235.     }
  236.     }
  237.   else
  238.     {
  239.       /* We want to start the search from the current history position. */
  240.       noninc_history_pos = where_history ();
  241.       if (noninc_search_string)
  242.     free (noninc_search_string);
  243.       noninc_search_string = savestring (rl_line_buffer);
  244.     }
  245.  
  246.   noninc_dosearch (noninc_search_string, dir);
  247. }
  248.  
  249. /* Search forward through the history list for a string.  If the vi-mode
  250.    code calls this, KEY will be `?'. */
  251. rl_noninc_forward_search (count, key)
  252.      int count, key;
  253. {
  254.   if (key == '?')
  255.     noninc_search (1, '?');
  256.   else
  257.     noninc_search (1, 0);
  258.   return 0;
  259. }
  260.  
  261. /* Reverse search the history list for a string.  If the vi-mode code
  262.    calls this, KEY will be `/'. */
  263. rl_noninc_reverse_search (count, key)
  264.      int count, key;
  265. {
  266.   if (key == '/')
  267.     noninc_search (-1, '/');
  268.   else
  269.     noninc_search (-1, 0);
  270.   return 0;
  271. }
  272.  
  273. /* Search forward through the history list for the last string searched
  274.    for.  If there is no saved search string, abort. */
  275. rl_noninc_forward_search_again (count, key)
  276.      int count, key;
  277. {
  278.   if (!noninc_search_string)
  279.     {
  280.       ding ();
  281.       return (-1);
  282.     }
  283.   noninc_dosearch (noninc_search_string, 1);
  284.   return 0;
  285. }
  286.  
  287. /* Reverse search in the history list for the last string searched
  288.    for.  If there is no saved search string, abort. */
  289. rl_noninc_reverse_search_again (count, key)
  290.      int count, key;
  291. {
  292.   if (!noninc_search_string)
  293.     {
  294.       ding ();
  295.       return (-1);
  296.     }
  297.   noninc_dosearch (noninc_search_string, -1);
  298.   return 0;
  299. }
  300.  
  301. static int
  302. rl_history_search_internal (count, direction)
  303.      int count, direction;
  304. {
  305.   HIST_ENTRY *temp, *old_temp;
  306.   int line_len;
  307.  
  308.   maybe_save_line ();
  309.  
  310.   temp = old_temp = (HIST_ENTRY *)NULL;
  311.   while (count)
  312.     {
  313.       temp = (direction < 0) ? previous_history () : next_history ();
  314.       if (!temp)
  315.         break;
  316.       if (STREQN (rl_line_buffer, temp->line, rl_point))
  317.     {
  318.       /* Don't find multiple instances of the same line. */
  319.       if (prev_line_found && STREQ (prev_line_found, temp->line))
  320.         continue;
  321.           if (direction < 0)
  322.             old_temp = temp;
  323.           prev_line_found = temp->line;
  324.           count--;
  325.     }
  326.     }
  327.  
  328.   if (!temp)
  329.     {
  330.       if (direction < 0 && old_temp)
  331.     temp = old_temp;
  332.       else
  333.     {
  334.       maybe_unsave_line ();
  335.       ding ();
  336.       return 1;
  337.     }
  338.     }
  339.  
  340.   line_len = strlen (temp->line);
  341.   if (line_len >= rl_line_buffer_len)
  342.     rl_extend_line_buffer (line_len);
  343.   strcpy (rl_line_buffer, temp->line);
  344.   rl_undo_list = (UNDO_LIST *)temp->data;
  345.   rl_end = line_len;
  346.   return 0;
  347. }
  348.  
  349. /* Search forward in the history for the string of characters
  350.    from the start of the line to rl_point.  This is a non-incremental
  351.    search. */
  352. int
  353. rl_history_search_forward (count, ignore)
  354.      int count, ignore;
  355. {
  356.   if (count == 0)
  357.     return (0);
  358.   if (rl_last_func != rl_history_search_forward)
  359.     prev_line_found = (char *)NULL;
  360.   return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
  361. }
  362.  
  363. /* Search backward through the history for the string of characters
  364.    from the start of the line to rl_point.  This is a non-incremental
  365.    search. */
  366. int
  367. rl_history_search_backward (count, ignore)
  368.      int count, ignore;
  369. {
  370.   if (count == 0)
  371.     return (0);
  372.   if (rl_last_func != rl_history_search_backward)
  373.     prev_line_found = (char *)NULL;
  374.   return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
  375. }
  376.